package com.hzhr.iot.huaweiiot.service;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.hzhr.iot.core.constant.ServiceErrors;
import com.hzhr.iot.core.exception.ServiceException;
import com.hzhr.iot.core.util.HzhrDateUtil;
import com.hzhr.iot.huaweiiot.constant.Huaweiiot_ErrorsEnum;
import com.hzhr.iot.huaweiiot.dao.mapper.generator.HuaweiiotAppEntityMapper;
import com.hzhr.iot.huaweiiot.entity.HuaweiiotAppEntity;
import com.iotplatform.client.NorthApiClient;
import com.iotplatform.client.NorthApiException;
import com.iotplatform.client.dto.*;
import com.iotplatform.client.invokeapi.Authentication;
import com.iotplatform.client.invokeapi.DeviceManagement;
import com.iotplatform.client.invokeapi.SignalDelivery;
import com.iotplatform.utils.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class HuaweiIotService  {
	@Autowired
	HuaweiiotAppEntityMapper huaweiiotAppEntityMapper;
	@Autowired
	HuaweiIotService huaweiIotService;

	//region javadoc注释 : getTokenDto
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 获取tokenDto; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * HUAWEIIOTSERVICE_GET_TOKEN_DTO_201 : <br/>&nbsp&nbsp&nbsp&nbsp异常类型 : 业务流程异常<br/>&nbsp&nbsp&nbsp&nbsp异常业务 : 获取tokenDto<br/>&nbsp&nbsp&nbsp&nbsp异常描述 : 华为iot平台服务调用错误<br/>
     * HUAWEIIOTSERVICE_GET_TOKEN_DTO_202 : <br/>&nbsp&nbsp&nbsp&nbsp异常类型 : 业务流程异常<br/>&nbsp&nbsp&nbsp&nbsp异常业务 : 获取tokenDto<br/>&nbsp&nbsp&nbsp&nbsp异常描述 : 获取northApiClient失败<br/>
     * @see AuthOutDTO result <br/>
     */ 
	//endregion
	//region 说明 : getTokenDto
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 获取tokenDto; (√)
	//endregion
	public AuthOutDTO getTokenDto() throws ServiceException {
		try {
			//新建服务对象，并初始化，以鉴权为例
			NorthApiClient northApiClient = huaweiIotService.getNorthApiClient();
			Authentication auth = new Authentication(northApiClient);
			AuthOutDTO authOutDTO = null;
			//调用SDK API
			authOutDTO = auth.getAuthToken();
			return authOutDTO;
		} catch (NorthApiException e) {
			Map<String, Object> errorInfo = new HashMap<>();
			errorInfo.put("errorCode", e.getError_code());
			errorInfo.put("errorDes", e.getError_desc());
			throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_GET_TOKEN_DTO_201, errorInfo);
		} catch (ServiceException e) {
			ServiceErrors serviceErrors = e.getServiceErrors();
			if (Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_GET_NORTH_API_CLIENT_201.equals(serviceErrors)) {
				throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_GET_TOKEN_DTO_202);
			}

			throw e;
		}
	}

	//region javadoc注释 : getAccessToken
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 获取华为iot平台登录token; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * @see String result <br/>
     */ 
	//endregion
	//region 说明 : getAccessToken
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 获取华为iot平台登录token; (√)
	//endregion
	public String getAccessToken() throws ServiceException {
		HuaweiiotAppEntity huaweiiotappEntity = huaweiiotAppEntityMapper.selectByPrimaryKey(1);

		String accessToken = null;
		Date accessTokenExpirionTime = huaweiiotappEntity.getAccesstokenexpiriontime();
		if (accessTokenExpirionTime == null || accessTokenExpirionTime.getTime() < new Date().getTime()) {//当前令牌已过期
			AuthOutDTO authOutDTO = getTokenDto();
			accessToken = authOutDTO.getAccessToken();
			//更新token和过期时间
			huaweiiotappEntity.setCurrentaccesstoken(accessToken);
			Date expirationTime = HzhrDateUtil.strToDate(HzhrDateUtil.addTime(HzhrDateUtil.dateToStr(new Date()), authOutDTO.getExpiresIn(), "yyyy-MM-dd HH:mm:ss", Calendar.SECOND));
			huaweiiotappEntity.setAccesstokenexpiriontime(expirationTime);
			huaweiiotAppEntityMapper.updateByPrimaryKey(huaweiiotappEntity);

		} else {//当前令牌未过期
			accessToken = huaweiiotappEntity.getCurrentaccesstoken();
		}
		return accessToken;
	}

	//region javadoc注释 : postDeviceCommand
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 向华为iot平台的指定设备发送命令; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * @see PostDeviceCommandOutDTO result <br/><br/><br/>
     * @throws ServiceException <br/>
     * @see PostDeviceCommandOutDTO result <br/>
     */ 
	//endregion
	//region 说明 : postDeviceCommand
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 向华为iot平台的指定设备发送命令; (√)
	//endregion
	public PostDeviceCommandOutDTO postDeviceCommand(String accessToken, String deviceId, String command, Integer expireTime) throws ServiceException {
		try {
			NorthApiClient northApiClient = huaweiIotService.getNorthApiClient();
			SignalDelivery sd = new SignalDelivery();
			sd.setNorthApiClient(northApiClient);

			PostDeviceCommandInDTO pdcid = new PostDeviceCommandInDTO();
			pdcid.setDeviceId(deviceId);
			if (expireTime != null) {
				pdcid.setExpireTime(expireTime);
			}
			AsynCommandDTO acdo = new AsynCommandDTO();
			String serviceId = "General";
			String method = "SET";
			ObjectNode paras = null;
			try {
				paras = JsonUtil.convertObject2ObjectNode("{\"command\":\"" + command + "\"}");
			} catch (Exception e) {
				e.printStackTrace();
			}
			acdo.setServiceId(serviceId); acdo.setMethod(method);
			acdo.setParas(paras);
			pdcid.setCommand(acdo);
			PostDeviceCommandOutDTO pdcod = null;
			pdcod = sd.postDeviceCommand(pdcid, northApiClient.getClientInfo().getAppId(), accessToken);

			return pdcod;
		} catch (NorthApiException e) {
			Map<String, Object> errorInfo = new HashMap<>();
			errorInfo.put("errorCode", e.getError_code());
			errorInfo.put("errorDes", e.getError_desc());
			throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_POST_COMMAND_201, errorInfo);
		} catch (ServiceException e) {
			ServiceErrors serviceErrors = e.getServiceErrors();
			if (Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_GET_NORTH_API_CLIENT_201.equals(serviceErrors)) {
				throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_POST_COMMAND_202);
			}

			throw e;
		}
	}

	//region javadoc注释 : postDeviceCommand
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 向华为iot平台的指定设备发送命令; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * @see PostDeviceCommandOutDTO result <br/><br/><br/>
     * @throws ServiceException <br/>
     * @see PostDeviceCommandOutDTO result <br/>
     */ 
	//endregion
	//region 说明 : editDevice
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 向华为iot平台的指定设备发送命令; (√)
	//endregion
	public PostDeviceCommandOutDTO postDeviceCommand(String deviceId, String command) throws ServiceException {
		String accessToken = huaweiIotService.getAccessToken();
		int expireTime = 0;
		return postDeviceCommand(accessToken, deviceId, command, expireTime);
	}

	//region javadoc注释 : getNorthApiClient
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 获取northApiClient; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * HUAWEIIOTSERVICE_GET_NORTH_API_CLIENT_201 : <br/>&nbsp&nbsp&nbsp&nbsp异常类型 : 业务流程异常<br/>&nbsp&nbsp&nbsp&nbsp异常业务 : 获取northApiClient<br/>&nbsp&nbsp&nbsp&nbsp异常描述 : 华为iot平台服务调用错误<br/>
     * @see NorthApiClient result <br/>
     */ 
	//endregion
	//region 说明 : getNorthApiClient
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 获取northApiClient; (√)
	//endregion
	public NorthApiClient getNorthApiClient() throws ServiceException {
		try {
			HuaweiiotAppEntity huaweiiotappEntity = huaweiiotAppEntityMapper.selectByPrimaryKey(1);

			//1 新建对象NorthApiClient
			NorthApiClient northApiClient = new NorthApiClient();
			//2 初始化ClientInfo
			ClientInfo clientInfo = new ClientInfo();
			String appId = huaweiiotappEntity.getAppid();
			String secret = huaweiiotappEntity.getSecret();
			clientInfo.setAppId(appId);
			clientInfo.setPlatformIp(huaweiiotappEntity.getPlatformip());
			clientInfo.setPlatformPort(huaweiiotappEntity.getPlatformport());
			clientInfo.setSecret(secret);
			northApiClient.setClientInfo(clientInfo);
			//3 证书配置，使用默认调试证书可以如 下配置
			northApiClient.initSSLConfig();
			return northApiClient;
		} catch (NorthApiException e) {
			Map<String, Object> errorInfo = new HashMap<>();
			errorInfo.put("errorCode", e.getError_code());
			errorInfo.put("errorDes", e.getError_desc());
			throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_GET_NORTH_API_CLIENT_201, errorInfo);
		}
	}

	//region javadoc注释 : registerDevice
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 在华为iot平台上注册设备; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * HUAWEIIOTSERVICE_REGISTER_DEVICE_201 : <br/>&nbsp&nbsp&nbsp&nbsp异常类型 : 业务流程异常<br/>&nbsp&nbsp&nbsp&nbsp异常业务 : 在华为iot平台上注册设备<br/>&nbsp&nbsp&nbsp&nbsp异常描述 : 华为iot平台服务调用错误<br/>
     * @see RegDirectDeviceOutDTO result <br/>
     */ 
	//endregion
	//region 说明 : registerDevice
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 在华为iot平台上注册设备; (√)
	//endregion
	public RegDirectDeviceOutDTO registerDevice(String accessToken, String nbIdentity, String deviceName) throws ServiceException {
		try {
			NorthApiClient northApiClient = huaweiIotService.getNorthApiClient();
			DeviceManagement dm = new DeviceManagement(northApiClient);
			//注册
			RegDirectDeviceInDTO rddid = new RegDirectDeviceInDTO();
			rddid.setNodeId(nbIdentity);
			rddid.setVerifyCode(nbIdentity);
			rddid.setTimeout(0);
			RegDirectDeviceOutDTO rddod = null;
			rddod = dm.regDirectDevice(rddid, northApiClient.getClientInfo().getAppId(), accessToken);

			//修改设备属性
			System.out.println(rddod.getDeviceId());
			editDevice(accessToken, rddod.getDeviceId(), deviceName);
			return rddod;
		} catch (NorthApiException e) {
			Map<String, Object> errorInfo = new HashMap<>();
			errorInfo.put("errorCode", e.getError_code());
			errorInfo.put("errorDes", e.getError_desc());
			throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_REGISTER_DEVICE_201, errorInfo);
		}
	}

	//region javadoc注释 : editDevice
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 向华为iot平台的指定设备发送命令; (√) <br/>
     * 获取tokenDto <br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 在华为iot平台上编辑设备; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * HUAWEIIOTSERVICE_EDIT_DEVICE_201 : <br/>&nbsp&nbsp&nbsp&nbsp异常类型 : 业务流程异常<br/>&nbsp&nbsp&nbsp&nbsp异常业务 : 在华为iot平台上编辑设备<br/>&nbsp&nbsp&nbsp&nbsp异常描述 : 华为iot平台服务调用错误<br/>
     */ 
	//endregion
	//region 说明 : editDevice
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 在华为iot平台上编辑设备; (√)
	//endregion
	public void editDevice(String accessToken, String iotSerialNum, String deviceName) throws ServiceException {
		try {
			NorthApiClient northApiClient = huaweiIotService.getNorthApiClient();
			DeviceManagement dm = new DeviceManagement(northApiClient);
			ModifyDeviceInfoInDTO mdiid = new ModifyDeviceInfoInDTO();
			mdiid.setName(deviceName);
			mdiid.setDeviceId(iotSerialNum);
			mdiid.setManufacturerId("Hzhr");
			mdiid.setManufacturerName("Hzhr");
			mdiid.setDeviceType("GasMeter");
			mdiid.setModel("NBIoTDeviceTest");
			mdiid.setProtocolType("CoAP");
			dm.modifyDeviceInfo(mdiid, northApiClient.getClientInfo().getAppId(), accessToken);
		} catch (NorthApiException e) {
			Map<String, Object> errorInfo = new HashMap<>();
			errorInfo.put("errorCode", e.getError_code());
			errorInfo.put("errorDes", e.getError_desc());
			throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_EDIT_DEVICE_201, errorInfo);
		}
	}

	//region javadoc注释 : deleteDevice
    /**
     * 获取tokenDto <br/><br/>
     * 范围 : 内部服务 <br/>
     * 步骤 : <br/>
     * 1. 在华为iot平台上删除设备; (√) <br/><br/><br/>
     * @throws ServiceException <br/>
     * HUAWEIIOTSERVICE_DELETE_DEVICE_201 : <br/>&nbsp&nbsp&nbsp&nbsp异常类型 : 业务流程异常<br/>&nbsp&nbsp&nbsp&nbsp异常业务 : 在华为iot平台上删除设备<br/>&nbsp&nbsp&nbsp&nbsp异常描述 : 华为iot平台服务调用错误<br/>
     */ 
	//endregion
	//region 说明 : deleteDevice
	//获取tokenDto
	//范围 : 内部服务
	//步骤 :
	//1. 在华为iot平台上删除设备; (√)
	//endregion
	public void deleteDevice(String accessToken, String iotSerialNum) throws ServiceException {
		try {
			NorthApiClient northApiClient = huaweiIotService.getNorthApiClient();
			DeviceManagement dm = new DeviceManagement(northApiClient);
			dm.deleteDirectDevice(iotSerialNum, northApiClient.getClientInfo().getAppId(), accessToken);
		} catch (NorthApiException e) {
			Map<String, Object> errorInfo = new HashMap<>();
			errorInfo.put("errorCode", e.getError_code());
			errorInfo.put("errorDes", e.getError_desc());
			throw new ServiceException(Huaweiiot_ErrorsEnum.HUAWEIIOTSERVICE_DELETE_DEVICE_201, errorInfo);
		}

	}

}












